#pragma once
// MySQL 版本
#include "../comm/util.hpp"
#include "../comm/log.hpp"
#include "include/mysql.h"

#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <fstream>
#include <cstdlib>
#include <cassert>

// 根据题目list文件，加载所有的题目信息到内存中
// model: 主要用来和数据进行交互，对外提供访问数据的接口

namespace ns_model
{
    using namespace std;
    using namespace ns_log;
    using namespace ns_util;

    struct Question
    {
        std::string number; // 题目编号，唯一
        std::string title;  // 题目的标题
        std::string star;   // 难度: 简单 中等 困难
        std::string desc;   // 题目的描述
        std::string header; // 题目预设给用户在线编辑器的代码
        std::string tail;   // 题目的测试用例，需要和header拼接，形成完整代码
        int cpu_limit;      // 题目的时间要求(S)
        int mem_limit;      // 题目的空间要去(KB)
    };

    const std::string oj_questions = "oj_questions";
    const std::string host = "127.0.0.1";
    const std::string user = "oj_client";
    const std::string passwd = "123456";
    const std::string db = "oj";
    const int port = 3306;

    class MySQLConnection
    {
    public:
        MySQLConnection()
        {
            my_ = mysql_init(nullptr);
            if (!my_)
            {
                LOG(FATAL) << "初始化 MySQL 失败!" << "\n";
                throw std::runtime_error("初始化 MySQL 失败!");
            }

            if (!mysql_real_connect(my_, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0))
            {
                LOG(FATAL) << "连接数据库失败: " << mysql_error(my_) << "\n";
                mysql_close(my_);
                throw std::runtime_error("连接数据库失败: " + std::string(mysql_error(my_)));
            }

            if (mysql_set_character_set(my_, "utf8") != 0)
            {
                LOG(WARNING) << "设置字符编码失败: " << mysql_error(my_) << "\n";
            }

            LOG(INFO) << "连接数据库成功!" << "\n";
        }

        ~MySQLConnection()
        {
            if (my_)
            {
                mysql_close(my_);
            }
        }

        MYSQL* get() const
        {
            return my_;
        }

    private:
        MYSQL* my_;
    };

    class Model
    {
    public:
        Model() {}

        bool QueryMySql(const std::string &sql, std::vector<Question> *out)
        {
            try
            {
                MySQLConnection conn;

                // 执行sql语句
                if (mysql_query(conn.get(), sql.c_str()) != 0)
                {
                    LOG(WARNING) << sql << " 执行错误: " << mysql_error(conn.get()) << "\n";
                    return false;
                }

                LOG(INFO) << "SQL 语句执行成功" << "\n";

                // 提取结果
                MYSQL_RES *res = mysql_store_result(conn.get());
                if (!res)
                {
                    LOG(WARNING) << "获取结果集失败: " << mysql_error(conn.get()) << "\n";
                    return false;
                }

                // 分析结果
                int rows = mysql_num_rows(res); // 获得行数量
                int cols = mysql_num_fields(res); // 获得列数量

                for (int i = 0; i < rows; i++)
                {
                    MYSQL_ROW row = mysql_fetch_row(res);
                    if (!row)
                    {
                        LOG(WARNING) << "获取行数据失败" << "\n";
                        continue;
                    }

                    Question q;
                    q.number = row[0];
                    q.title = row[1];
                    q.star = row[2];
                    q.desc = row[3];
                    q.header = row[4];
                    q.tail = row[5];
                    q.cpu_limit = std::stoi(row[6]);
                    q.mem_limit = std::stoi(row[7]);

                    out->push_back(q);
                }

                // 释放结果集
                mysql_free_result(res);
                return true;
            }
            catch (const std::exception &e)
            {
                LOG(ERROR) << "数据库操作异常: " << e.what() << "\n";
                return false;
            }
        }

        bool GetAllQuestions(vector<Question> *out)
        {
            std::string sql = "SELECT * FROM " + oj_questions;
            return QueryMySql(sql, out);
        }

        bool GetOneQuestion(const std::string &number, Question *q)
        {
            std::string sql = "SELECT * FROM " + oj_questions + " WHERE number = '" + number + "'";
            vector<Question> result;
            if (QueryMySql(sql, &result))
            {
                if (result.size() == 1)
                {
                    *q = result[0];
                    return true;
                }
            }
            return false;
        }

        ~Model() {}
    };
} // namespace ns_model